package com.noodles.mall.aspect;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.noodles.mall.entity.*;
import com.noodles.mall.exception.GlobalExceptionHandler;
import com.noodles.mall.service.ItemRecommendService;
import com.noodles.mall.service.OrderItemService;
import com.noodles.mall.util.Constant;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * 计算商品推荐指数
 */
@Aspect
@Component
public class ItemRecommendAddScore {

    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @Autowired
    private ItemRecommendService itemRecommendService;

    @Autowired
    private OrderItemService orderItemService;

    @Pointcut("execution(public * com.noodles.mall.controller.ItemController.selectById(..))")
    public void selectItemDetails() {
        System.out.println("ItemRecommendAddScore: selectById");
    }

    @Pointcut("execution(public * com.noodles.mall.controller.CartController.insert(..))")
    public void insertCart() {
        System.out.println("ItemRecommendAddScore: insert");
    }

    @Pointcut("execution(public * com.noodles.mall.controller.OrderController.insert(..))")
    public void insertOrder() {
        System.out.println("ItemRecommendAddScore: insert");
    }

    @Pointcut("execution(public * com.noodles.mall.controller.OrderController.update(..))")
    public void updateOrder() {
        System.out.println("ItemRecommendAddScore: update");
    }

    @Pointcut("selectItemDetails() || insertCart() || insertOrder() || updateOrder()")
    private void score() {
        System.out.println("ItemRecommendAddScore: score");
    }

    @Transactional(rollbackFor = RuntimeException.class)
    @AfterReturning("score()")
    public void afterMethod(JoinPoint joinPoint) {
        System.out.println("ItemRecommendAddScore: afterMethod 开始");
        System.out.println("joinPoint: "+joinPoint);
        String targetName = joinPoint.getSignature().getName();
        logger.info("after " + targetName + "...");
        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (principal instanceof User) {
            Double score = 0.0;
            switch (targetName) {
                case "selectItemDetails":
                    score = Constant.RECOMMEND_SCORE_1;
                    break;
                case "insertCart":
                    score = Constant.RECOMMEND_SCORE_2;
                    break;
                case "insertOrder":
                    score = Constant.RECOMMEND_SCORE_3;
                    break;
                case "updateOrder":
                    score = Constant.RECOMMEND_SCORE_4;
                    break;
            }
            List<Integer> itemIdList = new ArrayList<>();
            for (Object arg : joinPoint.getArgs()) {
                if (arg instanceof Integer) {
                    itemIdList.add((Integer) arg);
                } else if (arg instanceof Cart) {
                    Cart cart = (Cart) arg;
                    itemIdList.add(cart.getItemId());
                } else if (arg instanceof List) {
                    List<Cart> cartList = (ArrayList) arg;
                    cartList.stream().forEach(cart -> itemIdList.add(cart.getItemId()));
                } else if (arg instanceof Order) {
                    Order order = (Order) arg;
                    orderItemService.selectList(order.getId())
                            .forEach(orderItem -> itemIdList.add(orderItem.getItemId()));
                }
            }
            for (Integer itemId : itemIdList) {
                User user = (User) principal;
                Double addScore = Optional.ofNullable(itemRecommendService.getOne(new QueryWrapper<ItemRecommend>().lambda()
                        .eq(ItemRecommend::getItemId, itemId)
                        .eq(ItemRecommend::getUserId, user.getId())))
                        .map(itemRecommend -> itemRecommend.getScore()).orElse(0.0);
                ItemRecommend itemRecommend = new ItemRecommend();
                itemRecommend.setUserId(user.getId());
                itemRecommend.setItemId(itemId);
                itemRecommend.setScore(score + addScore > 10.0 ? 10.0 : score + addScore);
                itemRecommendService.saveOrUpdate(itemRecommend,
                        new UpdateWrapper<ItemRecommend>().lambda()
                                .eq(ItemRecommend::getItemId, itemRecommend.getItemId())
                                .eq(ItemRecommend::getUserId, itemRecommend.getUserId()));
            }
        }
        System.out.println("ItemRecommendAddScore: afterMethod 结束");
    }

}
